// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
use std::process::{Command, Stdio};
// 引入moka库中的同步缓存功能
use moka::sync::Cache;
// 引入portable_pty crate中的模块和类型，用于创建和管理伪终端(Pseudo-TTY)
use portable_pty::{native_pty_system, CommandBuilder, PtyPair, PtySize};
use std::{
    fs::{File, OpenOptions},
    io::{BufRead, BufReader, Read, Write},
    sync::Arc,
    thread, time,
};
// 异步运行时的 Mutex，用于线程间同步
use tauri::{async_runtime::Mutex as AsyncMutex, AppHandle, Builder, Emitter, EventTarget, State};
use uuid::Uuid;
use std::sync::{Mutex};

static RENODE_PROCESS: Mutex<Option<std::process::Child>> = Mutex::new(None);

//在repl文件后追加配置，repl为renode描述外设的文件，追加的配置为连接按钮和小灯泡
#[tauri::command]
fn add_repl(
    source: &str,
    target: &str,
    target_value: &str,
    interrupt_target: &str,
    interrupt_index: &str,
) {
    let mut file = OpenOptions::new()
        .append(true)
        .open("../platforms/stm32f103_user.repl")
        .expect("open error");
    let mut line1 = source.to_string();

    if source == "button" {
        line1.push_str(": Miscellaneous.Button @ ");
        line1.push_str(target);
        line1.push(' ');
        line1.push_str(target_value);
        line1.push('\n');
        file.write_all(line1.as_bytes()).expect("write error");
        let mut line2 = String::from("    ");
        if interrupt_target != "none" {
            line2.push_str("-> ");
            line2.push_str(interrupt_target);
            line2.push('@');
            line2.push_str(interrupt_index);
            line2.push_str("\n\n");
        }
        file.write_all(line2.as_bytes()).expect("write error");
    }
    if source == "LED" {
        line1.push_str(": Miscellaneous.LED @ ");
        line1.push_str(target);
        line1.push(' ');
        line1.push_str(target_value);
        line1.push_str("\n\n");
        file.write_all(line1.as_bytes()).expect("write error");

        let mut line2 = String::from(target);
        line2.push_str(":\n");
        line2.push_str("    ");
        line2.push_str(target_value);
        line2.push_str(" -> LED@0\n");

        file.write_all(line2.as_bytes()).expect("write error");
    }
}

//resc可以看作一个renode的批处理文件
//将要运行的elf文件加载到renode中，实际为在macro reset指令前添加$bin ?= @name
#[tauri::command]
fn add_resc(name: &str) -> String {
    // 文件路径
    let file_path = "../platforms/stm32f103.resc";
    // 打开文件
    let file = File::open(file_path).expect("open error");
    let reader = BufReader::new(file);

    let match_string = "macro reset";

    // 创建一个临时文件来保存修改后的内容
    let temp_file_path = "../platforms/stm32f103_temp.resc";
    let mut temp_file = File::create(temp_file_path).expect("create error");

    // 逐行读取文件内容
    for line in reader.lines() {
        let current_line = line.expect("line null");

        // 检查当前行是否包含匹配字符串
        if current_line.contains(match_string) {
            // 在匹配字符串之前插入新的字符串
            let mut insert_line = String::new();
            insert_line.push_str("$bin ?= @");
            insert_line.push_str(name);
            writeln!(temp_file, "{}", insert_line).expect("write error");
        }

        // 将当前行写入临时文件
        writeln!(temp_file, "{}", current_line).expect("write error");
    }
    std::fs::rename(temp_file_path, file_path).expect("rename error");
    name.to_owned()
}

#[tauri::command]
fn start(window: AppHandle) {
    // 启动 Renode 进程
    let renode_process = Command::new("renode")
        .arg("--console")
        .arg("-e")
        .arg("start @../platforms/stm32f103.resc")
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        //启动子进程，并返回一个结果
        .spawn()
        .expect("Failed to start Renode process");

    // 保存到全局变量
    let mut guard = RENODE_PROCESS.lock().unwrap();
    *guard = Some(renode_process);
    
    // 释放锁，避免在闭包中持有
    drop(guard);


    let mut guard = RENODE_PROCESS.lock().unwrap();
    if let Some(ref mut child) = *guard{
        if let Some(mut renode_stdin) = child.stdin.take() {
        // 创建新线程执行定时命令发送
        thread::spawn(move || {
            // 定义轮询间隔（每秒1次）
            let poll_interval = std::time::Duration::from_secs(1);
            loop {
                // 1. 发送Renode命令（"sysbus.gpioPortC.LED State"）
                let command = "sysbus.gpioPortC.LED State\n";  
                if let Err(e) = renode_stdin.write_all(command.as_bytes()) {
                    eprintln!("Failed to send command to Renode: {}", e);
                    break;
                }
                
                // 2. 立即刷新确保发送
                if let Err(e) = renode_stdin.flush() {
                    eprintln!("Flush error: {}", e);
                    break;
                }
                
                // 3. 等待下一个周期
                thread::sleep(poll_interval);
            }
        });
    }
    if let Some(stdout) = child.stdout.take() {
            let output_reader = BufReader::new(stdout);
            //复制window并将其赋值给w
            let w = window.clone();
            // 启动一个线程来读取 Renode 输出并发送到前端
            std::thread::spawn(move || {
                for line in output_reader.lines().filter(Result::is_ok).flatten() {
                    // 将每行输出发送到前端
                    let trimmed = line.trim();
                    if trimmed=="True"||trimmed=="False"{
                        let mut payload=false;
                        if trimmed=="True"{
                            payload=true;
                        }
                        println!("{}", payload);
                        w.emit_to(
                            EventTarget::webview_window("main"),
                            "LED_output",
                            Some(payload),
                        )
                        .unwrap();
                        }
                }
            });
        }
    }
    
    //log处理线程，查log，返回给main窗口的事件returned_command，内容为log中returned后面的文本
    std::thread::spawn(move || {
        let filename = "../logs/stm32f746_1";
        let mut last = 0;
        loop {
            //打开log文件
            thread::sleep(time::Duration::from_millis(100));
            let f = File::open(filename);
            //判断是否打开文件成功
            let f = if let Ok(f) = f {
                f
            } else {
                println!("文件读取失败");
                continue;
            };

            let bf = BufReader::new(f);
            let mut counter = 0;
            let mut content;
            for i in bf.lines().enumerate().skip(last) {
                counter = i.0;
                content = i.1.unwrap();
                // println!("last = {} counter: {}, content: {}", last, counter, content);
                let matched = parse(&content);
                if let Some(m) = matched {
                    println!("matched: {}", m);
                    // 向主窗口发送匹配到的命令
                    window.emit_to("main", "returned_command", Some(m)).unwrap();
                }
            }

            last = counter;


        }
    });
}


#[tauri::command]
fn stop(){
    if let Ok(mut guard) = RENODE_PROCESS.lock() {
        if let Some(mut child) = guard.take() {
            let _ = child.kill();
            let _ = child.wait();
        }
    }
}

fn parse(s: &str) -> Option<&str> {
    // 使用regex库来创建一个正则表达式对象，该正则表达式旨在匹配"returned"后面的任何文本。
    use regex::Regex;
    let regex = Regex::new(r"(?m)returned\s+(.*)$").unwrap();
    // 在输入字符串上迭代查找所有匹配的文本。
    let mut result = regex.captures_iter(s);
    if let Some(mat) = result.next() {
        //获取捕获组1，(.*)，即returned后面的文本
        let g = mat.get(1).unwrap();
        return Some(g.as_str());
    }
    None
}


#[tauri::command]
fn startrenode(window: AppHandle) {
        // 启动 Renode 进程
    let renode_process = Command::new("renode")
        .arg("--console")
        .arg("-e")
        .arg("start @../platforms/stm32f103.resc")
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        //启动子进程，并返回一个结果
        .spawn()
        .expect("Failed to start Renode process");
    if let Some(mut renode_stdin) = renode_process.stdin {
    // 创建新线程执行定时命令发送
    thread::spawn(move || {
        // 定义轮询间隔（每秒1次）
        let poll_interval = std::time::Duration::from_secs(1);
        loop {
            // 1. 发送Renode命令（"sysbus.gpioPortC.LED State"）
            let command = "sysbus.gpioPortC.LED State\n"; 
            if let Err(e) = renode_stdin.write_all(command.as_bytes()) {
                eprintln!("Failed to send command to Renode: {}", e);
                break;
            }
            
            // 2. 立即刷新确保发送
            if let Err(e) = renode_stdin.flush() {
                eprintln!("Flush error: {}", e);
                break;
            }
            
            // 3. 等待下一个周期
            thread::sleep(poll_interval);
        }
    });
    }
    if let Some(stdout) = renode_process.stdout {
            let output_reader = BufReader::new(stdout);
            //复制window并将其赋值给w
            let w = window.clone();
            // 启动一个线程来读取 Renode 输出并发送到前端
            std::thread::spawn(move || {
                for line in output_reader.lines().filter(Result::is_ok).flatten() {
                    // 将每行输出发送到前端
                    println!("{}",line);
                    let trimmed = line.trim();
                    if trimmed=="True"||trimmed=="False"{
                        let mut payload=false;
                        if trimmed=="True"{
                            payload=true;
                        }
                        println!("{}", payload);
                        w.emit_to(
                            EventTarget::webview_window("main"),
                            "LED_output",
                            Some(payload),
                        )
                        .unwrap();
                        }
                }
            });
        }
}
    





struct Terminal {
    // 它们被用于控制终端的输入和输出。
    //使用`AsyncMutex`来确保对这些设备文件的并发访问是线程安全的。
    pty_pair: AsyncMutex<PtyPair>,
    // `writer` 字段是一个异步安全的写入器，它包装了一个实现了`Write`和`Send` trait的对象。
    // 这允许从任何线程异步地向终端写入数据。
    writer: AsyncMutex<Box<dyn Write + Send>>,
    // 这允许从任何线程异步地读取终端的输出。
    reader: AsyncMutex<BufReader<Box<dyn Read + Send>>>,
}



#[tauri::command]
fn local_path()->String{
    let current_dir = std::env::current_dir().unwrap();
    current_dir.to_str().unwrap().to_string()
}
struct AppState {
    /// 存储终端的缓存，键为终端的字符串标识，值为Terminal的Arc指针
    terminals: Cache<String, Arc<Terminal>>,
}

//异步函数创建一个shell会话
#[tauri::command]
async fn create_shell(
    //应用程序句柄，用于后续事件发射
    app: AppHandle,
    //应用程序状态，用于存储终端信息
    state: State<'_, AppState>,
    //终端的行数
    rows: u16,
    //终端的列数
    cols: u16,
) -> Result<String, String> {
    #[cfg(target_os = "windows")]
    let mut cmd = CommandBuilder::new("powershell.exe");

    #[cfg(target_os = "linux")]
    let mut cmd = CommandBuilder::new("bash");

    #[cfg(target_os = "macos")]
    let mut cmd = CommandBuilder::new("zsh");

    #[cfg(target_os = "windows")]
    cmd.env("TERM", "cygwin");

    #[cfg(not(target_os = "windows"))]
    cmd.env("TERM", "xterm-256color");
    // 创建PTY系统并打开一个伪终端
    let pty_system = native_pty_system();
    let pty_pair = pty_system
        .openpty(PtySize {
            rows,
            cols,
            pixel_width: 0,
            pixel_height: 0,
        })
        .map_err(|err| err.to_string())?;
    // 使用pty_pair的从属端口来启动命令
    let mut child = pty_pair
        .slave
        .spawn_command(cmd)
        .map_err(|err| err.to_string())?;
    // 尝试从pty_pair的master端克隆一个读取器对象
    let reader = pty_pair
        .master
        .try_clone_reader()
        // 如果克隆过程中发生错误，将错误转换为字符串并返回
        .map_err(|e| e.to_string())?;
    let writer = pty_pair.master.take_writer().map_err(|e| e.to_string())?;

    let terminal_id = Uuid::new_v4().to_string();

    let terminal = Arc::new(Terminal {
        writer: AsyncMutex::const_new(Box::new(writer)),
        reader: AsyncMutex::const_new(BufReader::new(reader)),
        pty_pair: AsyncMutex::new(pty_pair),
    });
    state
        .terminals
        .insert(terminal_id.clone(), terminal.clone());

    let id = terminal_id.clone();

    thread::spawn(move || {
        let status = child.wait().unwrap();
        println!("Terminal {} exited with status {}", id, status);
        app.emit("exit_terminal", id).unwrap();
    });

    Ok(terminal_id)
}

#[tauri::command]
/// 本函数尝试从应用状态中找到指定ID的终端。如果找到，它会异步获取终端的写入锁，
/// 然后将数据写入终端。如果写入操作成功，则返回`Ok(())`；如果写入操作失败，
/// 则返回`Err(())`。如果未找到指定ID的终端，则直接返回`Err(())`。
async fn write_pty(
    terminal_id: String,
    data: String,
    state: State<'_, AppState>,
) -> Result<(), ()> {
    // 尝试从状态中获取指定ID的终端
    if let Some(terminal) = state.terminals.get(&terminal_id) {
        // 异步获取终端的写锁，并尝试写入数据
        write!(terminal.writer.lock().await, "{}", data).map_err(|_| ())?;
        Ok(())
    } else {
        // 如果未找到指定ID的终端，返回错误
        Err(())
    }
}


#[tauri::command]
//终端的唯一标识符，用于查找对应的终端。
//状态对象，包含应用程序的状态和已连接终端的信息。
async fn read_pty(terminal_id: String, state: State<'_, AppState>) -> Result<Option<String>, ()> {
    if let Some(terminal) = state.terminals.get(&terminal_id) {
        // 获取并锁定终端的reader，以便读取PTY数据
        let reader = &mut terminal.reader.lock().await;
        let data = {
            // 尝试从reader中填充缓冲区，如果发生错误，则忽略错误并返回()
            let data = reader.fill_buf().map_err(|_| ())?;
            // 检查填充的数据是否非空
            if !data.is_empty() {
                // 将缓冲区的数据转换为UTF-8字符串，并将结果封装为Some
                std::str::from_utf8(data)
                    .map(|v| Some(v.to_string()))
                    .map_err(|_| ())?
            } else {
                 // 如果数据为空，则返回None
                None
            }
        };

        if let Some(data) = &data {
            reader.consume(data.len());
        }

        Ok(data)
    } else {
        Err(())
    }
}


#[tauri::command]
//异步调整PTTY（伪终端）大小。
/// 遍历应用状态中的所有终端，调整每个终端的PTTY大小到指定的行数和列数。
/// 使用锁来确保并发安全，因为每个终端的PTTY调整操作是异步的。
async fn resize_pty(rows: u16, cols: u16, state: State<'_, AppState>) -> Result<(), ()> {
    for (_, terminal) in state.terminals.iter() {
        terminal
            .pty_pair
            .lock()
            .await
            .master
            .resize(PtySize {
                rows,
                cols,
                ..Default::default()
            })
            .map_err(|_| ())?;
    }
    Ok(())
}

#[tauri::command]
/// 异步函数：关闭终端
async fn close_terminal(terminal_id: String, state: State<'_, AppState>) -> Result<(), ()> {
    if let Some(_terminal) = state.terminals.remove(&terminal_id) {
        Ok(())
    } else {
        Err(())
    }
}


#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    println!("{}",local_path());
    let dir_path = "../platforms";
    

    // 检查目录是否存在
    if !std::path::Path::new(dir_path).exists() {
            match std::fs::create_dir_all(dir_path) {
                Ok(_) => println!("创建成功: {}", dir_path),
                Err(e) => eprintln!("创建失败: {}", e),
            }
        } 
    else {
        println!("目录已存在: {}", dir_path);
    }
    // 创建并打开一个文件用于写入，这个文件将存储有关平台的配置信息
    let mut file = File::create("../platforms/stm32f103_user.repl").expect("create error");
    //测试代码
    file.write_all(b"using \"../platforms/cpus/stm32f103.repl\" \n\n")
        .expect("write error");
    //解除占用使得renode可以使用
    drop(file);

    Builder::new()
        .plugin(tauri_plugin_dialog::init())
        .plugin(tauri_plugin_fs::init())
        .manage(AppState {
            terminals: Cache::new(100),
        })
        // .manage(TerminalState { output_buffer: output_buffer.clone() })
        .invoke_handler(tauri::generate_handler![
            add_repl,
            add_resc,
            start,
            write_pty,
            resize_pty,
            create_shell,
            read_pty,
            close_terminal,
            local_path,
            startrenode,
            stop
        ])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}
